// A wrap for codemirror(http://codemirror.net/)
xui.Class("RAD.expression.CodeEditor", ["xui.UI.Widget", "xui.absValue"], {
    Instance: {
        activate: function () {
            var profile = this.get(0);
            if (profile.$cm) profile.$cm.focus();
            if (profile.$cm) profile.$cm.doc.setCursor(profile.readonly_head || 0 + 1, 0);
            return this;
        },
        getCM: function () {
            return this.get(0).$cm;
        },
        resetEditorStyle: function (theme, fs, lineWrapping, cm) {
            this.addCMTheme(theme);

            var profile = this.get(0);
            if (!cm) cm = profile.$cm;
            if (cm) {
                cm.setOption("theme", theme);
                cm.setOption("lineWrapping", !!lineWrapping);
                var n = cm.getWrapperElement();
                if (n) {
                    n.style.fontSize = fs + "px";
                }
            }
        },
        showModeSelDlg: function (mm) {
            var ns = this,
                cm = ns.getCM(),
                profile = ns.get(0),
                callback = function (mode) {
                    // force to finish render
                    if (!mode || mode.mode === "none") {
                        if (!profile.$initialized)
                            profile.$initialized = true;
                        if (profile.onRendered)
                            profile.boxing().onRendered(profile, true);
                    } else {
                        cm.setOption('mode', mode.mime || mode.mode);
                        CodeMirror.autoLoadMode(cm, mode.mode);

                        if (profile.onCodeModeSet)
                            profile.boxing().onCodeModeSet(profile, mode);
                    }
                    profile = cm = null;
                };
            xui.ModuleFactory.newCom("RAD.expression.SelRenderMode", function () {
                this.setEvents("onSel", callback);
                this.mainDlg.showModal();
                this.modeList.setValue(mm.mime + ":" + mm.mode);
            });
        },
        addCMTheme: function (theme) {
            var profile = this.get(0);
            var id = "cm-theme-" + theme;
            if (theme != "default" && !xui.CSS.get("id", id)) {
                xui.CSS.includeLink("codemirror5/theme/" + theme + ".css", false, id)
            }
        },
        clearHistory: function () {
            var obj = this.get(0).$cm;
            if (obj) obj.clearHistory();
        },
        reindent: function () {
            var cm = this.get(0).$cm,
                doc = cm.doc;
            if (doc.somethingSelected()) {
                var p1 = doc.getCursor("start"),
                    p2 = doc.getCursor("end");
                for (var i = p1.line, l = p2.line; i <= l; i++)
                    cm.indentLine(i)
            } else {
                var p1 = doc.firstLine(),
                    p2 = doc.lastLine();
                for (var i = p1, l = p2; i <= l; i++)
                    cm.indentLine(i)
            }
        },
        callEditor: function (name, args, isDoc) {
            var obj = this.get(0).$cm;
            if (isDoc) obj = obj.doc;
            return obj[name].apply(obj, args || []);
        },
        searchCode: function (code) {
            var profile = this.get(0),
                cm = profile.$cm;
            if (cm) {
                var cursor = cm.getSearchCursor(code, cm.hasFocus() ? cm.doc.getCursor() : {pos: 0, line: 0}, true);
                if (cursor.findNext()) {
                    cm.focus();
                    cm.doc.setSelection(cursor.from(), cursor.to());
                }
            }
        },
        // locate to declare key
        locateTo: function (key1, key2, toSelect) {
            var ns = this,
                profile = this.get(0),
                cm = profile.$cm,
                struct, info, codefrom, codeto;
            if (cm) {
                struct = RAD.ClassTool.getClassStruct2(cm.doc.getValue());
                if (key1) {
                    if (key2 && (key1 == "Static" || key1 == "Instance"))
                        info = xui.get(struct, ["sub", key1, "sub", key2]);
                    else
                        info = xui.get(struct, ["sub", key1]);
                }
                if (info) {
                    if (toSelect)
                        cm.doc.setSelection(cm.doc.posFromIndex(info.from), cm.doc.posFromIndex(info.to));
                    else {
                        var pos = cm.doc.posFromIndex(info.from);
                        cm.focus();
                        cm.doc.setCursor(pos);
                        cm.scrollIntoView(pos);
                    }
                    return true;
                }
            }
            return false;
        },
        focusLine: function (line) {
            var ns = this,
                profile = this.get(0),
                cm = profile.$cm,
                pos = {line: line, ch: 0};
            if (cm) {
                cm.focus();
                cm.doc.setCursor(pos);
                cm.scrollIntoView(pos);
            }
        },
        getLine: function (key1, key2, toSelect) {
            var ns = this,
                profile = this.get(0),
                cm = profile.$cm,
                struct, info, codefrom, codeto;
            if (cm) {
                struct = RAD.ClassTool.getClassStruct2(cm.doc.getValue());
                if (key1) {
                    if (key2 && (key1 == "Static" || key1 == "Instance"))
                        info = xui.get(struct, ["sub", key1, "sub", key2]);
                    else
                        info = xui.get(struct, ["sub", key1]);
                }
                if (info) {
                    return cm.doc.posFromIndex(info.from);
                }
            }
            return null;
        },
        // add code to a hash, or replace the original one
        addCodeInto: function (key1, key2, code, isFun, comments) {
            comments = comments || "";
            var ns = this,
                profile = this.get(0),
                cm = profile.$cm;
            if (cm) {
                var struct = RAD.ClassTool.getClassStructWithScope(cm.getValue()),
                    fo = xui.get(struct, ["sub", key1, "sub", key2]),
                    fo2;
                // There is a function => replace code
                if (fo/* && (fo.type=='function'||fo.type=='object')*/) {
                    cm.doc.replaceRange(code, cm.doc.posFromIndex(fo.from), cm.doc.posFromIndex(fo.to));
                    //cm.doc.setSelection(cm.doc.posFromIndex(fo.from), cm.doc.posFromIndex(fo.from+code.length));
                    //ns.reindent();
                } else {
                    if (comments) comments += "\n";

                    fo = xui.get(struct, ["sub", key1]);
                    // add first layer
                    if (!fo) {
                        fo2 = xui.get(struct, ["sub", struct.arr[struct.arr.length - 1]]);
                        if (fo2)
                            code = ",\n" + comments + key1 + ":{\n" + key2 + ":" + (isFun ? 'function()' : '') + code + "\n" + "}";
                        else {
                            code = key1 + ":{\n" + comments + key2 + ":" + (isFun ? 'function()' : '') + code + "\n" + "}\n";
                            fo2 = struct;
                            fo2.to--;
                        }
                    } else {
                        // find the last one
                        fo2 = xui.get(fo, ["sub", fo.arr[fo.arr.length - 1]]);
                        if (fo2)
                            code = ",\n" + comments + key2 + ":" + (isFun ? 'function()' : '') + code;
                        else {
                            code = comments + key2 + ":" + (isFun ? 'function()' : '') + code + "\n";
                            fo2 = fo;
                            fo2.to--;
                        }
                    }
                    var pos = cm.doc.posFromIndex(fo2.to);
                    cm.doc.replaceRange(code, pos, pos);
                    cm.doc.setSelection(pos, cm.doc.posFromIndex(fo2.to + code.length));
                    ns.reindent();
                }
                //locate in the UI
                //ns.locateTo(key1,key2);
            }
        },
        getBlockInfo: function (key1, key2) {
            var ns = this,
                profile = this.get(0),
                cm = profile.$cm;
            return cm && xui.get(RAD.ClassTool.getClassStructWithScope(cm.getValue()), ["sub", key1, "sub", key2]);
        },
        _refreshCM: function () {
            if (this.get(0).$cm) this.get(0).$cm.refresh();
        },


        _setCtrlValue: function (value) {
            if (!xui.isSet(value)) value = '';
            return this.each(function (profile) {
                if (profile.$cm && profile.$cm.getValue() != value) {
                    profile.$cm.doc.setValue(value);
                    if (profile.$tm1) profile.$tm1.clear();
                    if (profile.$tm2) profile.$tm2.clear();
                    delete profile.$tm1;
                    delete profile.$tm2;
                    delete profile.readonly_head;
                    delete profile.readonly_tail;
                }
            });
        },


        _getCtrlValue: function () {
            var profile = this.get(0);
            if (profile.$cm)
                return profile.$cm.doc.getValue();
            else
                return profile.properties.$UIvalue;
        },
        setReadonlyLines: function (head, tail) {
            var profile = this.get(0), doc = profile.$cm.doc;
            if (profile.$tm1) profile.$tm1.clear();
            if (profile.$tm2) profile.$tm2.clear();

            if (head) {
                profile.$tm1 = doc.markText({line: 0, ch: 0}, {line: head, ch: 0}, {
                    atomic: true,
                    readOnly: true,
                    css: 'background-color:#ccc;'
                });
            }
            if (tail) {
                var last = doc.lastLine();
                profile.$tm2 = doc.markText({line: last - tail}, {line: last}, {
                    atomic: true,
                    readOnly: true,
                    css: 'background-color:#ccc;'
                });
            }
            profile.readonly_head = head;
            profile.readonly_tail = tail;
        }
    },
    Initialize: function () {
        //modify default template for shell
        var t = this.getTemplate();
        xui.merge(t.FRAME.BORDER, {
            BOX: {
                tagName: 'div'
            }
        }, 'all');
        this.setTemplate(t);

        this.__trim = function (s) {
            if (/[^\s\uFEFF\xA0]/.test(s)) {
                return xui.str.trim(s);
            } else
                return s;
        };
    },
    Static: {
        $tempsandbox: "_$temp_for_xui_sandbox",
        $tempsandbox2: "_$temp_for_xui_sandbox2",
        $temppool: "_$temp_for_xui_pool",
        Appearances: {
            BOX: {
                width: '100%',
                height: '100%',
                left: 0,
                top: 0,
                position: 'absolute',
                background: '#fff'
            }
        },
        Behaviors: {},
        DataModel: {
            left: 0,
            top: 0,
            width: 200,
            height: 200,
            position: 'absolute',
            codeType: {
                ini: 'js',
                action: function (codeType) {
                    if (this.$cm) {
                        var mode = CONF.getRenderMode(codeType);
                        if (!mode) mode = CONF.getRenderMode("txt");
                        this.$cm.setOption('mode', mode.mime || mode.mode);
                        if (this.onCodeModeSet) this.boxing().onCodeModeSet(this, mode);
                    }
                }
            },
            readonly: {
                ini: false,
                action: function (value) {
                    if (this.$cm)
                        this.$cm.setOption("readOnly", !!value);
                }
            }
        },
        EventHandlers: {
            onValueChanged: function (profile, flag) {
            },
            onRendered: function (profile) {
            },
            onGetHelpInfo: function (profile, key) {
            },
            onCodeModeSet: function (profile, mode) {
            },
            onSaveCommand: function () {
            }
        },
        RenderTrigger: function () {
            var key = this.box.$temppool,
                subkey = this.$xid;

            this.box._loadEditor(this);

            this.destroyTrigger = function () {
                this.$cm.clearGutter();
                this.$cm.clearHistory();
                delete this.$cm;
                delete this.$tm1;
                delete this.$tm2;
                delete this.$editor;

                // destroy related UI
                if (this.$popList) this.$popList.destroy();
                if (this.$popHelp) this.$popHelp.destroy();
                if (this.$popCustom) this.$popCustom.destroy();

                if (window[key]) delete window[key][subkey];
            };
        },
        clearSandbox: function (name) {
            for (var i = 1, n; i < 9; i++) {
                n = name + i;
                if (n && document.getElementById(n)) {
                    document.body.removeChild(document.getElementById(n));
                    try {
                        delete frames[n]
                    } catch (e) {
                    }
                }
            }
        },
        purge: function () {
            var ns = this, z;
            if ((z = window[ns.$temppool]) && z.Instance && z.Instance._ctrlpool) {
                xui.each(z.Instance._ctrlpool, function (o, i) {
                    if (o && !o.destroyed) {
                        if (o.destroy) o.destroy();
                        if (o.boxing && o.boxing()) o.boxing().destroy();
                    }
                });
                xui.breakO(z.Instance);
            }
        },
        _alias: 1,
        evalInSandbox: function (code, funScope, name, subCacheKey, purge, beforeCode, afterCode, cleanFun) {
            if (name && document.getElementById(name)) {
                document.body.removeChild(document.getElementById(name));
                try {
                    delete frames[name]
                } catch (e) {
                }
            }
            var ns = this,
                iframe = document.createElement("iframe"), result, wnd, line, errmsg, type;

            ns.purge();

            if (name) {
                iframe.name = name;
                iframe.id = name;
            }


            iframe.src = "about:blank";
            iframe.style.display = "none";
            document.body.appendChild(iframe);
            wnd = frames[frames.length - 1];
            wnd.document.open();
            wnd.document.write('<meta http-equiv="content-type" content="text/html; charset=utf-8" />');
            wnd.document.write("<script>\n");
            if (beforeCode) wnd.document.write(beforeCode);
            wnd.document.write(""
                // stop Node.js
                + "global=process=Buffer=require=module=exports=root=null;\n"

                // copy object
                + "window.xui=parent.xui;\n"
                + "window.Class=function(){return xui.Class.apply(xui,arguments);};\n"
                + "window.CONF={mixed_prop: xui.clone(parent.CONF.mixed_prop) };\n"

                + (CONF.SandBoxExtCode || "")

                //get this scope
                + "window.__cache={};window.__getThis=function(pname,type){\n"
                + "      if(__cache[pname+':'+type])return __cache[pname+':'+type];\n"
                + "      var obj=type==1?function(){}:{};\n"
                + "      if(pname){\n"
                + "          if(xui.isArr(pname)){\n"
                + "              xui.each(pname,function(cls){\n"
                + "                  cls=xui.SC(cls);\n"
                + "                  obj=xui.merge(obj, type==1?(cls||xui.Module):(cls?(new cls):(new xui.Module)),'all',true)\n"
                + "              });\n"
                + "          }else{\n"
                + "              pname=xui.SC(pname);\n"
                + "              obj=xui.merge(obj, type==1?(pname||xui.Module):(pname?(new pname):(new xui.Module)),'all',true)\n"
                + "          }\n"
                + "      }\n"
                + "      if(window['" + ns.$temppool + "'] && window['" + ns.$temppool + "']['" + subCacheKey + "']){\n"
                + "          obj=xui.merge(obj, window['" + ns.$temppool + "']['" + subCacheKey + "'][type==1?'Static':'Instance'],'all')\n"
                + "      }\n"
                + "      return __cache[pname+':'+type]=obj;\n"
                + "  };\n"

                + "window['" + ns.$temppool + "']=parent['" + ns.$temppool + "'];\n"
                // "var b=arguments.callee;" for fix firefox 3.5 bug
                + "parent['" + ns.$tempsandbox + "']=/*@cc_on !@*/0?this:{eval:function(s){return (function(){var b=arguments.callee;return window.eval.call(window,s)})()}};\n"
                + "parent['" + ns.$tempsandbox2 + "']={getErrLine:function(s,cb){window.onerror=function(){cb.apply(null,arguments);return true;};var n=document.createElement('script');n.type='text/javascript';if(/*@cc_on !@*/0){n.text=s;}else{n.appendChild(document.createTextNode(s));};document.body.appendChild(n);window.onerror=null;}};\n"
                + "try{top=parent=null;}catch(e){}"
            );
            if (afterCode) wnd.document.write(afterCode);
            wnd.document.write("<\/script><body><span id='abc'></span></body>");
            wnd.document.close();
            var bak = xui.Dom.pack,
                bak1 = xui.absProfile.prototype.$link,
                bak11 = xui.absObj.$pickAlias,
                bak12 = xui.UIProfile.prototype.setDomId,
                bak2 = xui.require,
                bak3 = xui.$cache,
                bak4 = xui.asyRun,
                bak5 = xui.resetRun,
                bak6 = xui.exec,
                bak7 = xui.pseudocode._callFunctions;

            try {
                // avoid lib or dom affected
                xui.Dom.pack = function () {
                    var o = new xui.Dom(false), d = document.getElementById('abc');
                    o._nodes = [d];
                    return o
                };
                xui.absProfile.prototype.$link = function () {
                    return this;
                };
                // stop all default events
                xui.Class.$instanceCreated = function (instance) {
                    instance.$inDesign = 1;
                };
                xui.absObj.$pickAlias = function () {
                    return ns._alias++
                };
                xui.UIProfile.prototype.setDomId = function () {
                    return this;
                };
                xui.require = function () {
                };
                xui.$cache = {};
                xui.each(bak3, function (o, i) {
                    xui.$cache[i] = xui.isArr(o) ? [] : {};
                });
                xui.asyRun = xui.resetRun = xui.exec = xui.pseudocode._callFunctions = function () {
                };

                result = window[ns.$tempsandbox].eval(code);
                if (funScope) {
                    if (typeof(result) == 'function') result.call(funScope);
                }

                type = (result === wnd || result === wnd.content) ? 'window' :
                    result === wnd.console ? 'console' :
                        result === wnd.history ? 'history' :
                            result === wnd.screen ? 'screen' :
                                result === wnd.location ? 'location' :
                                    result === wnd.navigator ? 'navigator' :
                                        result === wnd.document ? 'document' :
                                            null;
                // to avoid : Can't execute code from a freed script
                if (xui.browser.newie || (xui.browser.ie && xui.browser.ver >= 9)) {
                    var fun = function (hash) {
                        for (var i in hash) {
                            if (xui.isFun(hash[i])) hash[i]._____string = hash[i] + "";
                            else if (xui.isHash(hash[i])) fun(hash[i]);
                            else if (xui.isArr(hash[i])) fun(hash[i]);
                        }
                    };
                    if (type === null && (xui.isHash(result) || xui.isArr(result))) fun(result);
                }
            } catch (e) {
                //firefox or opera
                if (xui.isSet(e.line || e.lineNumber)) {
                    line = e.line || e.lineNumber;
                }
                // safari chrome IE
                else {
                    var base = 0;
                    if (xui.browser.ie) {
                        window[ns.$tempsandbox2].getErrLine("var _a={;", function (a, b, c) {
                            base = c - 1;
                            return true;
                        });
                    }
                    window[ns.$tempsandbox2].getErrLine(code, function (a, b, c) {
                        line = c - base;
                        return true;
                    });
                }
                errmsg = ((e.name ? e.name + ' : ' : '') + (e.description || e.message || '') + (line ? '\n line : ' + line : ''));
                if (!xui.isSet(line) && /.*at line ([\d]+).*/.test(errmsg))
                    line = errmsg.replace(/.*at line ([\d]+).*/, '$1');
            } finally {

                if (purge) ns.purge();

                delete xui.Class.$instanceCreated;

                xui.Dom.pack = bak;
                xui.absProfile.prototype.$link = bak1;
                xui.absObj.$pickAlias = bak11;
                xui.UIProfile.prototype.setDomId = bak12;
                xui.require = bak2;
                xui.$cache = bak3;
                xui.asyRun = bak4;
                xui.resetRun = bak5;
                xui.exec = bak6;
                xui.pseudocode._callFunctions = bak7;

                if (cleanFun) cleanFun(wnd, iframe);

                wnd.CONF = wnd.Class = wnd.xui = wnd[ns.$temppool] = wnd.__getThis = wnd.__cache = null;
                if (CONF.ClearSandBoxExtCode) {
                    CONF.ClearSandBoxExtCode(wnd);
                }
                window[ns.$tempsandbox] = null;
                window[ns.$tempsandbox2] = null;

                var rsl = {
                    ok: result,
                    type: type,
                    ko: errmsg,
                    line: line
                };

                ns = bak = result = line = errmsg = type = null;
                if (!name)
                    document.body.removeChild(iframe);
                iframe = null;

                return rsl;
            }
        },
        _buildItem: function (id, type, key, o, caption, value, order, itemStyle) {
            return {
                id: id,
                caption: caption || id,
                value: value || id,
                tag: (order || (type == 'property' ? 'b' : type == 'function' ? 'c' : type == 'class' ? 'd' : type == 'event' ? 'e' : 'a')) + ":" + id.toLowerCase(),
                path: (key ? (key + ".") : "") + id,
                itemStyle: itemStyle,
                imageClass: !type ? null :
                    (type == 'property' ?
                        (xui.isSet(o) && xui.isHash(o)) ? 'spafont spa-icon-hash' :
                            (xui.isSet(o) && xui.isArr(o)) ? 'spafont spa-icon-array' :
                                'spafont spa-icon-var' :
                        type == 'var' ? 'spafont spa-icon-var' :
                            type == 'event' ? 'spafont spa-icon-action' :
                                type == 'function' ? 'spafont spa-icon-function' :
                                    type == 'class' ? 'spafont spa-icon-class' :
                                        "spafont spa-icon-prop")
            };
        },
        _intellcache: {},
        _enumKeys: function (target, key, normalObj, ownOnly) {
            // non-object or array return empty array
            if (!xui.isObj(target) || xui.isArr(target)) return [];

            // default is normal object
            normalObj = normalObj !== false;
            var ns = this,
                isxuiobj = target.$xui$,
                o, isfun,
                list = [];

            for (var i in target) {
                if ('prototype' == i || 'constructor' == i)
                    continue;
                if (isxuiobj) {
                    if ('upper' == i || 'After' == i || 'Before' == i || 'Instance' == i || 'Static' == i || 'Constructor' == i)
                        continue
                }
                try {
                    if (i.charAt(0) != "_" && i.charAt(0) != "$" && /^[\w_]+$/.test(i)) {
                        o = target[i];
                        if (normalObj && (o && o.$abstract)) {
                            continue;
                        }

                        isfun = typeof o == 'function' && (!(o && o.$xui$) || o.$asFunction);

                        if (ownOnly && (!target.hasOwnProperty(i) || !target.propertyIsEnumerable(i))) {
                            continue;
                        }
                        var value = i;
                        if (isfun) {
                            if (normalObj) {
                                var arr = xui.fun.args(o);
                                var isInstance = false;
                                if (xui.str.endWith(key, ".prototype")) {
                                    isInstance = true;
                                }
                                var paras = RAD.ClassTool.getArgsFromAPI(key.replace(".prototype", ""), i, isInstance);
                                if (paras) {
                                    // use doc's paramters
                                    arr = [];
                                    for (var k = 0, l = paras.length; k < l; k++) {
                                        arr[k] = paras[k] && paras[k].name;
                                    }
                                }
                                value = i + "(" + arr.join(", ") + ")";
//                                console.log(key.replace(".prototype",""), i , isInstance, arr, value);
                            } else {
                                value = i + "( )";
                            }
                        }
                        list.push(ns._buildItem(i,
                            (typeof o == 'function') ? (o && o.$xui$ && !o.$asFunction) ? 'class' : (o && o.$event$) ? "event" : 'function' : 'property',
                            key,
                            o,
                            value,
                            value
                        ));
                    }
                } catch (e) {
                    console.log(e);
                }

            }

            return list;
        },


        _getIntellisenseList: function (key, cachedata) {
            if (!key) return null;
            cachedata = cachedata !== false;

            var ns = this,
                cache = ns._intellcache,
                buildItem = ns._buildItem;

            if (cachedata && cache[key]) return cache[key];

            var list = [];
            if (key == ns.$temppool) {
                return [];
            }

            switch (key) {
                case ' variables ': {
                    list = [
                        // global
                        buildItem("xui", 0, 0, 0, 0, 0, 2, "font-weight:bold;color:#ff0000;"),
                        buildItem("xui()", 0, 0, 0, "xui()", "xui()", 2, "font-weight:bold;color:#ff0000;"),

                        buildItem("top", 0, 0, 0, 0, 0, 3, "font-weight:bold;"),
                        buildItem("parent", 0, 0, 0, 0, 0, 3, "font-weight:bold;"),
                        buildItem("window", 0, 0, 0, 0, 0, 3, "font-weight:bold;"),
                        buildItem("document", 0, 0, 0, 0, 0, 3, "font-weight:bold;"),
                        buildItem("navigator", 0, 0, 0, 0, 0, 3, "font-weight:bold;"),
                        buildItem("history", 0, 0, 0, 0, 0, 3, "font-weight:bold;"),
                        buildItem("location", 0, 0, 0, 0, 0, 3, "font-weight:bold;"),
                        buildItem("screen", 0, 0, 0, 0, 0, 3, "font-weight:bold;"),
                        buildItem("Math", 0, 0, 0, 0, 0, 3, "font-weight:bold;"),
                        buildItem("Number", 0, 0, 0, 0, 0, 3, "font-weight:bold;"),
                        buildItem("console", 0, 0, 0, 0, 0, 3, "font-weight:bold;"),
                        // js
                        buildItem("if  ", 0, 0, 0, "if...", "if(){\n\n}", 5),
                        buildItem("ifelse", 0, 0, 0, "if...else...", "if(){\n\n}else{\n\n}", 5),
                        buildItem("while", 0, 0, 0, "while...", "while(){\n\n};", 5),
                        buildItem("do  ", 0, 0, 0, "do...while", "do{\n\n}while();", 5),
                        buildItem("try  ", 0, 0, 0, "try...catch...finally", "try{\n\n}catch(e){\n\n}finally{\n\n}", 5),
                        buildItem("for  ", 0, 0, 0, "for...", "for(;;;){\n\n}", 5),
                        buildItem("forin  ", 0, 0, 0, "for...in", "for( in ){\n\n}", 5),
                        buildItem("function", 0, 0, 0, "function...", "function(){\n\n}", 5),
                        buildItem("switch", 0, 0, 0, "switch...", "switch(){\n  case : \n\n  break;\n  case : \n\n  break;\ndefault: \n\n}", 5),
                        buildItem("with", 0, 0, 0, "with...", "with(){\n\n}", 5),

                        buildItem("return", 0, 0, 0, "return", "return ", 4),
                        buildItem("break", 0, 0, 0, "break", "break;", 4),
                        buildItem("continue", 0, 0, 0, "continue", "continue;", 4),
                        buildItem("throw", 0, 0, 0, "throw", "throw ", 4),
                        buildItem("new ", 0, 0, 0, "new", "new ", 4),
                        buildItem("delete", 0, 0, 0, "delete", "delete ", 4),
                        buildItem("arguments", 0, 0, 0, "arguments", "arguments", 4),
                        buildItem("var", 0, 0, 0, "var", "var ", 4),
                        buildItem("case", 0, 0, 0, "case", "case :", 4),
                        buildItem("default", 0, 0, 0, "default", "default :", 4),

                        buildItem("typeof", 0, 0, 0, "typeof", "typeof ", 4),
                        buildItem("instanceof", 0, 0, 0, "instanceof", "instanceof ", 4),

                        buildItem("void", 0, 0, 0, "void", "void", 4),
                        buildItem("true", 0, 0, 0, "true", "true", 4),
                        buildItem("false", 0, 0, 0, "false", "false", 4),
                        buildItem("null", 0, 0, 0, "null", "null", 4),
                        buildItem("NaN", 0, 0, 0, "NaN", "NaN", 4),
                        buildItem("undefined", 0, 0, 0, "undefined", "undefined", 4),
                        buildItem("Infinity", 0, 0, 0, "Infinity", "Infinity", 4),


                        buildItem("decodeURI()", "function"),
                        buildItem("decodeURIComponent()", "function"),
                        buildItem("encodeURI()", "function"),
                        buildItem("encodeURIComponent()", "function"),
                        buildItem("escape()", "function"),
                        buildItem("eval()", "function"),
                        buildItem("isFinite()", "function"),
                        buildItem("parseFloat()", "function"),
                        buildItem("parseInt()", "function"),
                        buildItem("unescape()", "function"),
                        buildItem("Number()", "function"),
                        buildItem("String()", "function"),

                        //**********************
                        buildItem("keySet[", 0, 0, 0, "PK[0]", "PK[0]", 5),
                        buildItem("PK", 0, 0, 0, "PK['0']", "PK['0']", 4, "font-weight:bold;"),
                        buildItem("absField", 0, 0, 0, "absField()", "absField(filed1,filed2,value,units)", 5)
                    ];
                    break;
                }
                case 'new': {
                    list = [

                        buildItem("String", "class", 0, 0, 0, "String();", 1),
                        buildItem("Object", "class", 0, 0, 0, "Object();", 1),
                        buildItem("Array", "class", 0, 0, 0, "Array();", 1),
                        buildItem("RegExp", "class", 0, 0, 0, "RegExp();", 1),
                        buildItem("Boolean", "class", 0, 0, 0, "Boolean();", 1),
                        buildItem("Number", "class", 0, 0, 0, "Number();", 1),
                        buildItem("Date", "class", 0, 0, 0, "Date();", 1),

                        buildItem("xui.Dom", "class", 0, 0, 0, "xui.Dom();", 2),
                        buildItem("xui.UIProfile", "class", 0, 0, 0, "xui.UIProfile();", 2),
                        buildItem("xui.Module", "class", 0, 0, 0, "xui.Module();", 2),
                        buildItem("xui.Template", "class", 0, 0, 0, "xui.Template();", 2),
                        buildItem("xui.UI", "class", 0, 0, 0, "xui.UI();", 2),
                        buildItem("xui.DataBinder", "class", 0, 0, 0, "xui.DataBinder();", 2)
                    ];
                    for (var i in xui.UI) {
                        if (i != 'upper' && xui.UI[i].$xui$) {
                            list.push(buildItem("xui.UI." + i, "class", 0, 0, 0, " " + "xui.UI." + i + "();", 2));
                        }
                    }
                    break;
                }
                case 'history':
                case 'screen':
                    break;

                case 'PK[':
                    buildItem("PK['0']", 0, 0, 0, "PK['0']", "PK[0]", 5)
                    break;

                case 'console':
                    list = [
                        buildItem("log()", "function", key)
                    ];
                    break;
                case 'arguments': {
                    list = [
                        buildItem("callee", "property", key),
                        buildItem("length", "property", key)
                    ];
                    break;
                }
                case 'arguments.callee': {
                    list = [
                        buildItem("caller", "property", key),
                        buildItem("length", "property", key),
                        buildItem("call()", "function", key),
                        buildItem("apply()", "function", key)
                    ];
                    break;
                }
                case 'top':
                case 'parent':
                case 'window': {
                    var iframe = document.createElement("iframe");
                    iframe.style.display = "none";
                    document.body.appendChild(iframe);
                    var target = frames[frames.length - 1];
                    list = ns._enumKeys(target, key, false);
                    document.body.removeChild(iframe);
                    break;
                }
                case 'document': {
                    var iframe = document.createElement("iframe");
                    iframe.style.display = "none";
                    document.body.appendChild(iframe);
                    var target = frames[frames.length - 1];
                    list = ns._enumKeys(target.document, key, false);
                    document.body.removeChild(iframe);
                    break;
                }
                case 'Element.prototype': {
                    var iframe = document.createElement("iframe");
                    iframe.style.display = "none";
                    document.body.appendChild(iframe);
                    var target = frames[frames.length - 1];
                    target.document.write("<span>a</span>");
                    list = ns._enumKeys(target.document.body.firstChild, key, false);
                    document.body.removeChild(iframe);
                    break;
                }
                case 'Math': {
                    list = [
                        buildItem("E", "property", key),
                        buildItem("LN2", "property", key),
                        buildItem("LN10", "property", key),
                        buildItem("LOG2E", "property", key),
                        buildItem("LOG10E", "property", key),
                        buildItem("PI", "property", key),
                        buildItem("SQRT1_2", "property", key),
                        buildItem("SQRT2", "property", key),
                        buildItem("abs(x)", "function", key),
                        buildItem("acos(x)", "function", key),
                        buildItem("asin(x)", "function", key),
                        buildItem("atan(x)", "function", key),
                        buildItem("atan2(y,x)", "function", key),
                        buildItem("ceil(x)", "function", key),
                        buildItem("cos(x)", "function", key),
                        buildItem("exp(x)", "function", key),
                        buildItem("floor(x)", "function", key),
                        buildItem("log(x)", "function", key),
                        buildItem("max(x,y,z,...,n)", "function", key),
                        buildItem("min(x,y,z,...,n)", "function", key),
                        buildItem("pow(x,y)", "function", key),
                        buildItem("random()", "function", key),
                        buildItem("round(x)", "function", key),
                        buildItem("sin(x)", "function", key),
                        buildItem("sqrt(x)", "function", key),
                        buildItem("tan(x)", "function", key)
                    ];
                    break;
                }
                case 'Number': {
                    list = [
                        buildItem("MAX_VALUE", "property", key),
                        buildItem("MIN_VALUE", "property", key),
                        buildItem("NEGATIVE_INFINITY", "property", key),
                        buildItem("POSITIVE_INFINITY", "property", key)
                    ];
                    break;
                }
                case "Array.prototype": {
                    list = [
                        buildItem("length", "property", key),
                        buildItem("concat()", "function", key),
                        buildItem("join()", "function", key),
                        buildItem("pop()", "function", key),
                        buildItem("push()", "function", key),
                        buildItem("reverse()", "function", key),
                        buildItem("shift()", "function", key),
                        buildItem("sort()", "function", key),
                        buildItem("concat()", "function", key),
                        buildItem("splice()", "function", key),
                        buildItem("toString()", "function", key),
                        buildItem("unshift()", "function", key)
                    ];
                    break;
                }
                case "Date.prototype": {
                    list = [
                        buildItem("getDate()", "function", key),
                        buildItem("getDay()", "function", key),
                        buildItem("getFullYear()", "function", key),
                        buildItem("getHours()", "function", key),
                        buildItem("getMilliseconds()", "function", key),
                        buildItem("getMinutes()", "function", key),
                        buildItem("getMonth()", "function", key),
                        buildItem("getTime()", "function", key),
                        buildItem("getSeconds()", "function", key),
                        buildItem("getTimezoneOffset()", "function", key),
                        buildItem("getUTCDate()", "function", key),
                        buildItem("getUTCDay()", "function", key),
                        buildItem("getUTCFullYear()", "function", key),
                        buildItem("getUTCHours()", "function", key),
                        buildItem("getUTCMilliseconds()", "function", key),
                        buildItem("getUTCMinutes()", "function", key),
                        buildItem("getUTCMonth()", "function", key),
                        buildItem("getUTCSeconds()", "function", key),
                        buildItem("getYear()", "function", key),
                        buildItem("parse()", "function", key),
                        buildItem("setDate()", "function", key),
                        buildItem("setFullYear()", "function", key),
                        buildItem("setHours()", "function", key),
                        buildItem("setMilliseconds()", "function", key),
                        buildItem("setMinutes()", "function", key),
                        buildItem("setMonth()", "function", key),
                        buildItem("setSeconds()", "function", key),
                        buildItem("setTime()", "function", key),
                        buildItem("setUTCDate()", "function", key),
                        buildItem("setUTCFullYear()", "function", key),
                        buildItem("setUTCHours()", "function", key),
                        buildItem("setUTCMilliseconds()", "function", key),
                        buildItem("setUTCMinutes()", "function", key),
                        buildItem("setUTCSeconds()", "function", key),
                        buildItem("setUTCMonth()", "function", key),
                        buildItem("setYear()", "function", key),
                        buildItem("toDateString()", "function", key),
                        buildItem("toGMTString()", "function", key),
                        buildItem("toLocaleDateString()", "function", key),
                        buildItem("toLocaleTimeString()", "function", key),
                        buildItem("toLocaleString()", "function", key),
                        buildItem("toString()", "function", key),
                        buildItem("toUTCString()", "function", key),
                        buildItem("toTimeString()", "function", key),
                        buildItem("UTC()", "function", key)
                    ];
                    break;
                }
                case "Number.prototype": {
                    list = [
                    buildItem("toExponential()", "function", key),
                        buildItem("toFixed()", "function", key),
                        buildItem("toPrecision()", "function", key),
                        buildItem("toString()", "function", key)
                ]
                    ;
                    break;
                }
                case "Boolean.prototype": {
                    list = [
                        buildItem("toString()", "function", key)
                    ];
                    break;
                }
                case "Function.prototype": {
                    list = [
                        buildItem("toString()", "function", key),
                        buildItem("call()", "function", key),
                        buildItem("apply()", "function", key)
                    ];
                    break;
                }
                case "RegExp.prototype": {
                    list = [
                        buildItem("global", "property", key),
                        buildItem("ignoreCase", "property", key),
                        buildItem("multiline", "property", key),
                        buildItem("lastIndex", "property", key),
                        buildItem("source", "property", key),
                        buildItem("compile()", "function", key),
                        buildItem("exec()", "function", key),
                        buildItem("test()", "function", key)
                    ];
                    break;
                }
                case "String.prototype": {
                    list = [
                        buildItem("length", "property", key),
                        buildItem("charAt()", "function", key),
                        buildItem("charCodeAt()", "function", key),
                        buildItem("concat()", "function", key),
                        buildItem("fromCharCode()", "function", key),
                        buildItem("indexOf()", "function", key),
                        buildItem("lastIndexOf()", "function", key),
                        buildItem("match()", "function", key),
                        buildItem("replace()", "function", key),
                        buildItem("search()", "function", key),
                        buildItem("slice()", "function", key),
                        buildItem("split()", "function", key),
                        buildItem("substr()", "function", key),
                        buildItem("substring()", "function", key),
                        buildItem("toLowerCase()", "function", key),
                        buildItem("toUpperCase()", "function", key)
                    ];
                    break;
                }
                case "Object.prototype": {
                    list = [
                        buildItem("toString()", "function", key, 0, 0, 0, 'z'),
                        buildItem("toLocaleString()", "function", key, 0, 0, 0, 'z'),
                        buildItem("hasOwnProperty(key)", "function", key, 0, 0, 0, 'z'),
                        buildItem("propertyIsEnumerable(key)", "function", key, 0, 0, 0, 'z'),
                        buildItem("isPrototypeOf(obj)", "function", key, 0, 0, 0, 'z')
                    ];
                    break;
                }
                default: {
                    if (/\.prototype$/.test(key)) {
                        // [[[[[ bak
                        var bak = xui.Dom.pack,
                            bak1 = xui.absProfile.prototype.$link,
                            bak11 = xui.absObj.$pickAlias;

                        xui.Dom.pack = function () {
                            var o = new xui.Dom(false), d = document.getElementById('abc');
                            o._nodes = [d];
                            return o
                        };
                        xui.absProfile.prototype.$link = function () {
                            return this;
                        };
                        xui.absObj.$pickAlias = function () {
                            return ns._alias++
                        };
                        // ]]]]]
                        try {
                            var target = eval("new " + key.replace(/\.prototype$/, ''));
                            list = ns._enumKeys(target, key);
                        } catch (e) {
                        } finally {
                            //[[[[[ restore
                            xui.Dom.pack = bak;
                            xui.absProfile.prototype.$link = bak1;
                            xui.absObj.$pickAlias = bak11;
                            //]]]]]
                        }
                    }

                    if (!list.length) {
                        var target = xui.get(window, key.split("."));
                        list = ns._enumKeys(target, key);
                        cachedata = false;
                    }
                }
            }

            if (cachedata)
                cache[key] = list;

            return list;
        },


        _getFromFunctionExp: function (code) {
            var type;
            if (/toString\([^)]*\)$/.test(code))
                type = 'String.prototype';
            // functions patterns
            else if (/^\s*\(?\s*new\s+([\wxui.]+)\s*\(?\s*[^)]*\)?\s*\)?(\s*\.\s*(set|on|before|after)[\w]+\s*\([^)]*\)\s*)*$/.test(code)) {
                code = code.replace(/^\s*\(?\s*new\s+([\wxui.]+)\s*\(?\s*[^)]*\)?\s*\)?(\s*\.\s*(set|on|before|after)[\w]+\s*\([^)]*\)\s*)*$/, "$1");
                type = code + '.prototype';
            }
            else if (/.*\.reBoxing\(([^)]*)\)(\s*\.\s*(set|on|before|after)[\w]+\s*\([^)]*\)\s*)*$/.test(code)) {
                code = code.replace(/.*\.reBoxing\(([^)]*)\)(\s*\.\s*(set|on|before|after)[\w]+\s*\([^)]*\)\s*)*$/, "$1");
                if (code)
                    type = code.replace(/[\'\"]/g, "") + '.prototype';
                else
                    type = 'xui.Dom.prototype';
            }
            else if (code.indexOf("xui.alert(") == 0 || code.indexOf("xui.prompt(") == 0 || code.indexOf("xui.pop(") == 0 || code.indexOf("xui.confirm(") == 0)
                type = 'xui.UI.Dialog.prototype';
            else if (code.indexOf("xui(") == 0 || code.indexOf("xui.use(") == 0)
                type = 'xui.Dom.prototype';
            else if (code.indexOf("xui.Thread(") == 0 || code.indexOf("xui.Ajax(") == 0
                || code.indexOf("xui.SAjax(") == 0 || code.indexOf("xui.IAjax(") == 0
                || code.indexOf("xui.JSONP(") == 0 || code.indexOf("xui.XDMI(") == 0)
                type = 'xui.Thread.prototype';
            else if (/.*\.(getRoot|getSubNode|getSubNodes)\s*\(\s*[^\)]*\)\s*$/.test(code))
                type = 'xui.Dom.prototype';
            else if (/.*\.getElementById\s*\(\s*[^\)]*\)\s*$/.test(code))
                type = 'Element.prototype';
            return type;
        },
        _getFromObject: function (target) {
            if (!xui.isSet(target))
                return null;
            else if (target === xui.str)
                return "xui.str";
            else if (target === xui.arr)
                return "xui.arr";
            else if (target === xui)
                return "xui";
            else if (target.$xui$) {
                if (typeof target == 'function')
                    return target.KEY;
                else
                    return target.KEY + ".prototype";
            } else if (xui.isArr(target))
                return "Array.prototype";
            else if (xui.isDate(target))
                return "Date.prototype";
            else if (xui.isReg(target))
                return "RegExp.prototype";
            else if (xui.isNumb(target))
                return "Number.prototype";
            else if (xui.isStr(target))
                return "String.prototype";
            else if (xui.isBool(target))
                return "Boolean.prototype";
            else if (xui.isFun(target))
                return "Function.prototype";
            else if (xui.isObj(target)) {
                return "Object.prototype";
            }
            // dont use xui.isHash here
        },
        _findVars: function (profile, tonode, braceId) {
            var ns = this,
                cm = profile.$editor,
                arr = [];
            if (cm && tonode) {
                var doc = cm.win.document,
                    isBr = function (elem) {
                        return elem.tagName == "BR" || elem.tagName == "br"
                    },
                    isB = function (elem) {
                        return elem.tagName == "B" || elem.tagName == "b"
                    },
                    elem = doc.body.firstChild,
                    scope = "",
                    cls, txt, temp = [], cursor;

                cursor = arr;

                cursor.push(["this", ""]);

                while ((elem = elem.nextSibling) && elem != tonode) {
                    if (isB(elem) && elem._uid && elem.id.charAt(0) == 'b') {
                        // if sibling {, jump to it's }
                        if (!braceId || braceId.indexOf(elem.id) !== 0) {
                            elem = doc.getElementById('e' + elem.id.slice(1));
                        } else {
                            scope = elem._uid;
                            // reset scope
                            xui.arr.each(temp, function (o) {
                                o[1] = scope;
                            });
                            arr = arr.concat(temp);
                        }
                        temp = [];
                        cursor = arr;
                    }

                    cls = ns.__trim(elem.className);
                    txt = ns.__trim(elem.currentText);

                    if (cls == 'js-keyword' && txt == "function") {

                        // find "function abc(){}"
                        while ((elem = elem.nextSibling) && elem != tonode && (isBr(elem) || ns.__trim(elem.className) == "whitespace" || ns.__trim(elem.className) == "js-comment")) ;
                        cls = ns.__trim(elem.className);
                        txt = ns.__trim(elem.currentText);
                        if (cls == 'js-variabledef') {
                            cursor.push([txt, scope]);
                        }

                        // temp find
                        cursor = temp;
                        cursor.push(["this", scope]);
                    }

                    if (cls == 'js-variabledef')
                        cursor.push([txt, scope]);
                }
            }
            return arr;
        },

        _$key: function (key) {
            ns = this;
            list = [
                ns._buildItem("$currPerson", 0, 0, 0, "$currPerson", "$currPerson", 5),
                ns._buildItem("$currPerson.name", 0, 0, 0, "name", "name", 5)
            ]
            if (key == '$') {
                xui.Ajax("/admin/el/searchKey", {
                    projectName: SPA.curProjectName
                }, function (txt) {
                    var obj = txt;
                    if (!obj || obj.error) {
                        xui.message("No module in this project!");
                    } else {
                        xui.arr.each(obj.data, function (o) {
                            var item = ns._buildItem(o.id, 0, 0, 0, o.desc, o.expression, 5);
                            list.push(item);
                        });
                    }
                }, null, null, {method: 'post', asy: false}).start();
            }
            ;
            if (xui.str.startWith(key, '$') && xui.str.endWith(key, ".")) {
                xui.Ajax("/admin/el/searchMethod", {
                    projectName: SPA.curProjectName,
                    key: key
                }, function (txt) {
                    var obj = txt;
                    if (!obj || obj.error) {
                        xui.message("No module in this project!");
                    } else {
                        xui.arr.each(obj.data, function (o) {
                            var item = ns._buildItem(o.id, 0, 0, 0, o.desc, o.lastStr, 5);
                            list.push(item);
                        });
                    }
                }, null, null, {method: 'post', asy: false}).start();

            }
            ;
            return list;
        },

        _getIntellisense: function (profile, key, index, nolist) {
            var ns = this,
                _this = RAD.ClassTool._this;


            // get type

            if (xui.str.startWith(key, '$')) {
                type = "$";
            } else {
                if (key.indexOf('new ') == 0) {
                    type = 'new';
                } else if (key.charAt(key.length - 1) == '.') {
                    type = "properties";
                    key = key.slice(0, -1);
                } else {
                    if (key.indexOf('.') != -1) {
                        type = "properties";
                        key = key.slice(0, key.lastIndexOf('.'));
                    } else {
                        // return avialable var
                        type = "var";
                    }
                }
                if (type == "properties") {
                    if (key.indexOf('(') != -1) {
                        type = "function";
                    }
                }
            }


            var target, code,
                list = [],
                // object type string
                otype,
                // object code string
                ocode,
                // extra array
                oextra = [];
            switch (type) {
                case 'new':
                    otype = type;
                    break;
                case '$':
                    list = this._$key(key);
                    break;
                case "function":
                    type = ns._getFromFunctionExp(key);
                    if (type) {
                        otype = type;
                        break;
                    }
                case "properties":
                    if (key == "arguments" || key == "arguments.callee") {
                        otype = key;
                        break;
                    } else {
                        // try exec all code dir
                        var arrcode = [],
                            vars = [],
                            code = profile.$cm.getValue(),
                            allcode = RAD.ClassTool.getContextAssignments(code, index),
                            struct = RAD.ClassTool.getClassStructWithScope(code, index, ns.$temppool, profile.$xid);

                        arrcode.push("(function(){try{\n");
                        arrcode.push("var " + _this + "=window;\n");
                        vars.push(_this);
                        var added1 = false, added2 = false,
                            len = allcode.vars.length;
                        for (var i = 0; i < len; i++) {
                            arrcode.push("var " + allcode.vars[i] + "=undefined;\n");
                            vars.push(allcode.vars[i]);
                        }
                        // run once at least
                        for (var i = -1; i < len; i++) {
                            // no assignment, or assignment is in special scope
                            if (allcode.scopeS == -1 || i >= allcode.scopeS) {
                                // add only once
                                if (!added1) {
                                    added1 = true;
                                    var o;
                                    // get scope info
                                    if (allcode.secondKey && allcode.secondType == "function") {
                                        o = xui.get(struct, ['sub', allcode.firstKey, 'sub', allcode.secondKey]);
                                    } else if (allcode.firstKey && allcode.firstType == "function") {
                                        o = xui.get(struct, ['sub', allcode.firstKey]);
                                    }
                                    if (o) {
                                        // add scope code
                                        arrcode.push("try{" + _this + "=" + o._this + "}catch(e){};\n");
                                        // add args code
                                        xui.arr.each(o.argsv, function (arg, i) {
                                            // no matching argument
                                            if (!o.args || !o.args[i]) return false;

                                            // use dynamic code first
                                            if (arg.code) {
                                                arrcode.push("try{" + o.args[i] + "=" + arg.code + "}catch(e){};\n");
                                                vars.push(o.args[i]);
                                            } else {
                                                if (/\.prototype$/.test(arg.type)) {
                                                    arrcode.push("try{" + o.args[i] + "=" + arg.type.replace(/(.+)(\.prototype)$/, "new $1();") + "}catch(e){};\n");
                                                    vars.push(o.args[i]);
                                                } else {
                                                    arrcode.push("try{" + o.args[i] + "=" + arg.type + "}catch(e){};\n");
                                                    vars.push(o.args[i]);
                                                }
                                            }
                                        });
                                    }
                                }
                            }
                            // out of special scope
                            if (allcode.scopeS != -1 && i >= allcode.scopeE) {
                                if (!added2) {
                                    added2 = true;
                                    arrcode.push("try{" + _this + "=window;}catch(e){};\n");
                                }
                            }
                            // ignore when i is -1
                            if (i >= 0) {
                                arrcode.push("try{" + allcode.vars[i] + "=" + allcode.code[i] + ";}catch(e){};\n");
                                vars.push(allcode.vars[i]);
                            }
                        }
                        if (allcode.scopeS != -1 && allcode.outscope) {
                            if (!added2) {
                                arrcode.push("try{" + _this + "={};}catch(e){};\n");
                            }
                        }

                        arrcode.push("return (" + key + ");\n}catch(e){}finally{\n");
                        xui.arr.removeValue(vars, key);
                        arrcode.push(vars.join("=") + "=null;\n");
                        arrcode.push("}\n}).call({});\n");
                        ocode = arrcode.join('').replace(/\bthis\b/g, _this);
//console.log(ocode);
                    }
                    break;
                case "var":
                    otype = " variables ";

                    // caching according to line
                    /*
                    var hash,cache=ns.__varscache||(ns.__varscache={});
                    if(cache[index]){
                        hash=cache[index];
                    }else{
                        cache=ns.__varscache={};
                        cache[index]=hash=RAD.ClassTool.getContextVars(profile.$cm.getValue(),index);
                    }
                   */
                    var hash = RAD.ClassTool.getContextVars_fast(profile.$cm, index);

                    if (hash["this"]) {
                        oextra.push(ns._buildItem("this", 0, 0, 0, 0, 0, 1, "color:#ff0000;"));
                        delete hash["this"];
                    }
                    if (hash["arguments"]) {
                        oextra.push(ns._buildItem("arguments", 0, 0, 0, 0, 0, 1, "color:#ff0000;"));
                        delete hash["arguments"];
                    }

                    xui.each(hash, function (o, i) {
                        oextra.push(ns._buildItem(i, "var", 0, 0, 0, 0, 1, "color:#666;"));
                    });
                    break;
            }
            // from extra array
            if (oextra && oextra.length) {
                if (!nolist)
                    Array.prototype.push.apply(list, oextra);
            }
            // then "from code"
            if (ocode) {
                result = ns.evalInSandbox(ocode, false, null, profile.$xid);
                if (xui.isSet(result.ok)) {
                    // if result.type exists, igonre result.ok
                    if (result.type)
                        otype = result.type;
                    else {
                        otype = ns._getFromObject(result.ok);
                        if (!nolist)
                            Array.prototype.push.apply(list, ns._enumKeys(result.ok, otype, true, true));
                    }
                }
            }
            // the last one is "from type"
            if (otype) {
                if (!nolist)
                    Array.prototype.push.apply(list, ns._getIntellisenseList(otype));
            }

            if (list.length) {
                list = xui.arr.removeDuplicate(list, 'id');

                xui.arr.stableSort(list, function (x, y) {
                    return x.tag > y.tag ? 1 : x.tag == y.tag ? 0 : -1;
                });
            }

            return [otype, list, key];
        },
        _loadEditor: function (profile) {
            var ns = this,
                _this = RAD.ClassTool._this;

            // is suggestion window showed
            var $suggestionShowed = false,
                $suggestionBaseScope = null,
                $suggestionBaseScopeShadow = null,
                showSuggetionID = "CodeEditor.showSuggetion.resetRun",
                adjustSuggetionID = "CodeEditor.adjustSuggetion.resetRun",
                $currentText = "",
                $willshowDotHint = false,
                // suggestion window for
                $activeWord;

            // get short Suggestion code
            var getShortContentCode = function (index) {
                var reg = /\s+/g,
                    arr = [],
                    extxt = "",
                    cm = profile.$cm,
                    pos = cm.doc.posFromIndex(index),
                    line = pos.line,
                    elem = cm.getTokenAt(pos),
                    prev = function (elem) {
                        if (elem.start === 0) {
                            pos.line--;
                            if (pos.line === 0) {
                                return null;
                            }
                            var line = cm.doc.getLine(pos.line);
                            if (line) {
                                pos.ch = line.length;
                            } else {
                                return null;
                            }
                        } else {
                            pos.ch = elem.start;
                        }
                        return cm.getTokenAt(pos);
                    };

                // for dblclick case, find key text
                if (!(elem.type === null && elem.string == ".")) {
                    extxt = ns.__trim(elem.string);
                    elem = prev(elem);
                }
                // for dot case
                if (elem && (elem.type === null && elem.string == ".")) {
                    do {
                        if (elem.type === null && elem.string == ".") {
                            // ignore space and comments
                            while (elem = prev(elem)) {
                                if (!(!elem || elem.type == "comment" || elem.type == "tab" || (elem.type === null && /^\s+$/.test(elem.string)))) {
                                    break;
                                }
                            }
                            if (elem) {
                                // for (xxx)
                                var con1 = "";
                                if (elem.type === null && elem.string === ")") {
                                    var deep1 = 0;
                                    do {
                                        if (elem.type === null && elem.string === ")")
                                            deep1++;
                                        if (elem.type === null && elem.string === "(")
                                            deep1--;
                                        if (elem.string)
                                            con1 = elem.string + con1;
                                    } while ((elem = prev(elem)) && deep1 !== 0)
                                }
                                if (elem) {
                                    if (elem.type == "property" || elem.type == 'variable' || elem.type == 'variable-2'
                                        || elem.type == 'xuiglobal'
                                        || (elem.type == "keyword" && elem.string == "this")) {
                                        arr.push(elem.string.replace(reg, '') + con1);
                                    } else if (con1) {
                                        arr.push(con1);
                                    } else {
                                        break;
                                    }

                                }
                            }
                        } else {
                            break;
                        }
                    } while (elem = prev(elem))
                }
                // for space case
                else if (elem && (elem.type == null && elem.string === " ")) {
                    // ignore space and comments
                    while (elem = prev(elem)) {
                        if (!(!elem || elem.type == "comment" || (elem.type == null && elem.string === " "))) {
                            break;
                        }
                    }
                    if (elem.type == "keyword" && elem.string == "new") {
                        extxt = "new " + extxt;
                    }
                }

                return (arr.length ? (arr.reverse().join('.') + '.') : "") + extxt;
            };

            var iniComponents = function () {
                // [[Code created by ESDUI RAD Studio
                var host = this, children = [], append = function (child) {
                    children.push(child.get(0))
                };

                append(
                    (new xui.UI.Pane)
                        .setHost(host, "$popList")
                        .setLeft(10)
                        .setTop(10)
                        .setWidth(300)
                        .setHeight(180)
                );

                host.$popList.append(
                    (new xui.UI.List)
                        .setHost(host, "$lstsug")
                        .setTheme("codemirror")
                        .setDirtyMark(false)
                        .setTop(18)
                        .setWidth(300)
                        .setHeight(162)
                        .setItemRow(true)
                        .setDisableHoverEffect(true)
                );

                host.$popList.append(
                    (new xui.UI.Block)
                        .setHost(host, "block1")
                        .setLeft(0)
                        .setTop(0)
                        .setWidth(300)
                        .setHeight(24)
                        .setBorderType("flat")
                );

                host.block1.append(
                    (new xui.UI.Label)
                        .setHost(host, "$objType")
                        .setLeft(6)
                        .setTop(2)
                        .setWidth(252)
                        .setCaption("")
                        .setHAlign("left")
                        .setCustomStyle({KEY: 'font-weight:bold;'})
                );

                append(
                    (new xui.UI.Block)
                        .setHost(host, "$popHelp")
                        .setLeft(410)
                        .setTop(10)
                        .setWidth(300)
                        .setHeight(180)
                        .setBorderType("flat")
                        .setOverflow('hidden')
                        .setBackground("#FFF8DC")
                );

                host.$popHelp.append(
                    (new xui.UI.Div)
                        .setHost(host, "$divhelp")
                        .setTheme("codemirror")
                        .setLeft(-1)
                        .setTop(19)
                        .setWidth(300)
                        .setHeight(160)
                        .setCustomStyle({"KEY": "overflow:auto; padding:4px;"})
                );

                host.$popHelp.append(
                    (new xui.UI.Block)
                        .setHost(host, "block3")
                        .setLeft(-1)
                        .setTop(-1)
                        .setWidth(300)
                        .setHeight(20)
                        .setBorderType("flat")
                );

                host.block3.append(
                    (new xui.UI.Link)
                        .setHost(host, "$linkAPI")
                        .setLeft('auto')
                        .setRight(2)
                        .setTop(1)
                        .setCaption("$RAD.JSEditor.clickapi")
                );

                host.block3.append(
                    (new xui.UI.Label)
                        .setHost(host, "$lblTips")
                        .setLeft(6)
                        .setTop(2)
                        .setWidth(133)
                        .setCaption("")
                        .setHAlign("left")
                );

                return children;

                // ]]Code created by ESDUI RAD Studio
            };

            var handle = {
                moveFocus: function (step) {
                    var list = profile.$lstsug,
                        items = list.get(0).properties.items,
                        length = items.length,
                        value = list.getUIValue(),
                        index = xui.arr.subIndexOf(items, 'id', value);
                    if (step === true) {
                        index = 0;
                    } else if (step === false) {
                        index = length - 1;
                    } else {
                        index += step;
                        if (index < 0) index = 0;
                        if (index > length - 1) index = length - 1;
                    }
                    if (items[index])
                        list.setUIValue(items[index].id, true);
                },
                close: function () {
                    hideSuggestion();
                },
                pick: function () {
                    var list = profile.$lstsug,
                        items = list.get(0).properties.items,
                        length = items.length,
                        value = list.getUIValue(),
                        index = xui.arr.subIndexOf(items, 'id', value);

                    if (items[index])
                        applySuggestion(items[index].value || items[index].caption);
                    hideSuggestion();
                }
            };
            var keyMap = {
                Up: function () {
                    handle.moveFocus(-1);
                },
                Down: function () {
                    handle.moveFocus(1);
                },
                PageUp: function () {
                    handle.moveFocus(-8, true);
                },
                PageDown: function () {
                    handle.moveFocus(8, true);
                },
                Home: function () {
                    handle.moveFocus(true);
                },
                End: function () {
                    handle.moveFocus(false);
                },
                Enter: function () {
                    handle.pick();
                },
                Tab: function () {
                    handle.pick();
                },
                Esc: function () {
                    handle.close();
                }
            };
            // show suggestion
            var showSuggestion = function (key, index, fromDot, dftTxt) {
                // get intellisense

                var rtn = profile.box._getIntellisense(profile, key, index),
                    keyword = rtn[0], ns = this,
                    items = rtn[1];
                dftTxt = dftTxt || key || "";

                if (!keyword && !(items && items.length)) {
                    hideSuggestion();
                    return;
                }


                if (!fromDot) {
                    var found = false, str = dftTxt.toLowerCase();
                    xui.arr.each(items, function (item) {
                        if (xui.str.startWith(item.id.toLowerCase(), str)) {
                            found = true;
                            return false;
                        }
                    });
                    if (!found) {
                        return;
                    }
                }
                var coordinates = cm.cursorCoords(true, "page"),
                    left = coordinates.left,
                    top = coordinates.top;

                if (!profile.$popList) {
                    iniComponents.call(profile);
                    xui('body').append(profile.$popList.setDisplay('none'));
                    xui('body').append(profile.$popHelp.setDisplay('none'));

                    profile.$divhelp.getRoot().setSelectable(true);

                    profile.$linkAPI.onClick(function (p) {
                        CONF.openAPI(p.properties.tag);
                    });
                    var out = true,
                        tryToClose = function () {
                            xui.resetRun("codemirror:aaa", function () {
                                if (out && profile.$popCustom) {
                                    profile.$popCustom.setDisplay('none');
                                }
                            });
                        };

                    profile.$lstsug.afterUIValueSet(function (profile, ov, v) {
                        showTips2(profile.getItemByItemId(v));
                    })
                        .onClick(function (profile, item) {
                            applySuggestion(item.value || item.caption);
                            hideSuggestion();
                        });
                }

                if ((items && items.length) || fromDot) {
                    $suggestionShowed = fromDot ? 1 : true;
                    if (items && items.length) {
                        profile.$lstsug.setItems(items);
                    }
                    var fun = function () {
                            hideSuggestion();
                        },
                        group = xui([profile.$popList.getRootNode(), profile.$popHelp.getRootNode(), profile.getSubNode("BOX").get(0)]);

                    profile.$popList.getRoot().popToTop({
                        region: {
                            left: left,
                            top: top,
                            width: 2,
                            height: 16
                        }
                    }, 1)
                        .setBlurTrigger(showSuggetionID, fun, group);
                    xui.Event.keyboardHook('esc', 0, 0, 0, fun);

                    profile.$popList.setDisplay('');

                    $activeWord = rtn[2] || null;

                    if (items && items.length) {
                        adjustSuggetion(left, top, dftTxt, "", true, true);
                    }
                }

                profile.$objType.setCaption(keyword || "none");

                // remove first
                profile.$cm.removeKeyMap(keyMap);
                profile.$cm.addKeyMap(keyMap);
            };

            // hide suggestion
            var hideSuggestion = function () {
                xui.Event.keyboardHook('esc', 0, 0, 0);

                profile.$cm.removeKeyMap(keyMap);

                xui.resetRun(showSuggetionID);
                xui.resetRun(adjustSuggetionID);

                $suggestionBaseScope = null;
                $suggestionBaseScopeShadow = null;
                $suggestionShowed = false;
                $willshowDotHint = false;

                if (profile.$popList) {
                    profile.$objType.setCaption('');
                    profile.$lstsug.setItems([]).setUIValue(null);
                    profile.$popList.setDisplay('none');

                    profile.$lblTips.setCaption('');
                    profile.$divhelp.setHtml("");
                    profile.$popHelp.setDisplay('none');

                    if (profile.$popCustom)
                        profile.$popCustom.setDisplay('none');

                    $currentText = null;
                }
            };

            // adjust selection and position for suggestion win
            var adjustSuggetion = function (left, top, txt, extxt, forVisibleOnly, asnyc) {
                if (!profile.$lstsug) return;
                var prf = profile.$lstsug.get(0),
                    items = prf.properties.items,
                    f = function () {
                        if (forVisibleOnly && !$suggestionShowed) return;

                        var fid;
                        if (extxt) txt += extxt;
                        if (!xui.isSet($currentText) || txt !== $currentText) {
                            $currentText = txt;
                            // try to find startWith
                            xui.arr.each(items, function (item) {
                                if (xui.str.startWith(item.id.toLowerCase(), $currentText.toLowerCase())) {
                                    fid = item.id;
                                    return false;
                                }
                            });
                            // try to find similiar
                            while (!fid && txt.length) {
                                txt = txt.substring(0, txt.length - 1);
                                if (!txt) break;
                                xui.arr.each(items, function (item) {
                                    if (xui.str.startWith(item.id.toLowerCase(), txt.toLowerCase())) {
                                        fid = item.id;
                                        return false;
                                    }
                                });
                            }
                            // the frist one
                            if (!fid) {
                                fid = items[0].id;
                            }
                        }
                        if (!prf.properties.$UIvalue && !fid && prf.properties.items && prf.properties.items.length)
                            fid = prf.properties.items[0].id;
                        if (fid)
                            prf.boxing().setUIValue(fid);
                        else {
                            hideSuggestion();
                            return;
                        }

                        // POSITION
                        profile.$popList.getRoot().popToTop({
                            region: {
                                left: left,
                                top: top,
                                width: 2,
                                height: 16
                            }
                        }, 1)
                        if (profile.$popHelp && profile.$popHelp.getDisplay() != 'none') {
                            profile.$popHelp.getRoot().popToTop(profile.$popList.getRoot(), 2)
                        }
                    };
                if (!asnyc)
                    f();
                else
                    xui.resetRun(adjustSuggetionID, f, 100);
            };

            var showTips = function (key, str) {
                if (!profile.$popHelp) return;
                if (profile.$popList.getDisplay() != 'none') {
                    profile.$linkAPI.setTag(key);
                    profile.$lblTips.setCaption(key);

                    profile.$divhelp.setHtml(str);
                    profile.$popHelp.getRoot().popToTop(profile.$popList.getRoot(), 2)
                    profile.$popHelp.setDisplay('');
                }
            };
            var hideTips = function (key, str) {
                if (!profile.$popHelp) return;

                profile.$linkAPI.setTag(null);
                profile.$lblTips.setCaption("");
                profile.$divhelp.setHtml("");
                profile.$popHelp.setDisplay("none");
            };
            // show tips
            var showTips1 = function (elem) {
                if (!profile.$popHelp) return;
                var key = getShortContentCode(elem);
                var str = profile.onGetHelpInfo && profile.boxing().onGetHelpInfo(profile, key.key);
//                if(!str)
//                    str=key.key;
                if (str) {
                    showTips(key.key, str);
                } else {
                    hideTips();
                }
            };
            var showTips2 = function (item) {
                if (!profile.$popHelp) return;
                if (!item) return;
                var str = profile.onGetHelpInfo && profile.boxing().onGetHelpInfo(profile, item.path);
//                if(!str)
//                   str=item.path;
                if (str) {
                    showTips(item.path, str);
                } else {
                    hideTips();
                }
            };

            // show Intellisense  from dot
            var showDotHint = function (index, scope, dftTxt, scopyShadow) {
                $suggestionBaseScope = $suggestionBaseScopeShadow = null;
                // hide list first
                //hideSuggestion();
                $willshowDotHint = true;
                xui.resetRun(showSuggetionID, function () {
                    var key = getShortContentCode(index);
                    if (!key) {
                        hideSuggestion();
                    } else {
                        $willshowDotHint = false;

                        if (key != dftTxt)
                            showSuggestion(key, index, true, dftTxt);
                    }
                }, 100);
                $suggestionBaseScope = scope;
                $suggestionBaseScopeShadow = scopyShadow;
            };
            // show vars hint
            var showVarsHint = function (key, index, scope) {
                xui.resetRun(showSuggetionID, function () {
                    showSuggestion(key, index);
                });
                // refresh
                $suggestionBaseScope = scope;
            };
            // show vars hint
            var tryToAdjustHint = function (key, index, scope) {
                var sc = $suggestionBaseScopeShadow || $suggestionBaseScope;
                if (sc && sc.line == scope.line && sc.start == scope.start) {
                    var coordinates = cm.cursorCoords(true, "page"),
                        left = coordinates.left,
                        top = coordinates.top;
                    adjustSuggetion(left, top, key, "", true);
                }
                // refresh
                $suggestionBaseScope = scope;
            };
            // apply suggestion to code
            var applySuggestion = function (value) {
                var editor = profile.$cm, o = $suggestionBaseScope;
                editor.replaceRange(value,
                    {line: o.line, ch: o.start},
                    {line: o.line, ch: o.end});

                // indentat multi line
                var line = o.line, hasE;
                value.replace(/\n/g, function () {
                    editor.indentLine(++line);
                    hasE = 1;
                });
                editor.setCursor({line: o.line + (hasE ? 1 : 0), ch: o.start + value.length});
                editor.execCommand("indentAuto");
            };
            var codeType = profile.properties.codeType,
                mode = CONF.getRenderMode(profile.properties.codeType);
            if (!mode) mode = CONF.getRenderMode("txt");

            // load codemirror
            var options = {
                value: profile.properties.value || "",
                smartIndent: true,
                indentUnit: 4,
                tabSize: 4,
                indentWithTabs: false,
                "mode": mode.mime,
                keyMap: "sublime",

                matchBrackets: true,
                continueComments: "Enter",
                autoCloseBrackets: true,
                lineNumbers: true,
                lint: (codeType == 'js' || codeType == 'json' || codeType == 'css' || codeType == 'html') ? true : false,
                readOnly: profile.properties.readonly,
                styleActiveLine: true,
                lineWrapping: false,
                flattenSpans: false,
                highlightSelectionMatches: {showToken: /^[$\w]\w*/},
                foldGutter: true,
                gutters: ["CodeMirror-lint-markers", "CodeMirror-linenumbers", "CodeMirror-foldgutter"],
                extraKeys: {
                    'Ctrl': function () {
                        hideSuggestion();
                    },
                    "Ctrl-Q": function (cm) {
                        cm.foldCode(cm.getCursor());
                    },
                    "Ctrl-S": function () {
                        hideSuggestion();
                        if (profile.onSaveCommand)
                            profile.boxing().onSaveCommand(profile);
                    },
                    "Ctrl-F": function (cm) {
                        hideSuggestion();
                        RAD.EditorTool.showFindWnd(profile.boxing(), {left: 0, top: 0}, cm.getSelection());
                    },
                    "Tab": function (cm) {
                        if (cm.doc.somethingSelected()) return CodeMirror.Pass;
                        var spaces = Array(cm.getOption("indentUnit") + 1).join(" ");
                        cm.replaceSelection(spaces, "end", "+input");
                    },
                    "Ctrl-D": function (cm) {
                        cm.execCommand("deleteLine");
                    }
                }
            };

            var obj = CONF.getStatus(),
                editorTheme = obj.editorTheme,
                editorFontSize = obj.editorFontSize,
                lineWrapping = obj.lineWrapping;

            if (editorTheme) {
                // include CSS first
                profile.boxing().addCMTheme(editorTheme);
                options.theme = editorTheme;
            }
            if (xui.isSet(lineWrapping)) {
                options.lineWrapping = !!lineWrapping;
            }

            var cm = profile.$cm = new CodeMirror(function (elt) {
                profile.getSubNode('BOX').append(elt);

                if (editorFontSize)
                    elt.style.fontSize = editorFontSize + "px";
            }, options);

            //cm.setOption("mode", mode);
            CodeMirror.modeURL = "/RAD/codemirror5/mode/%N/%N.js";

            CodeMirror.autoLoadMode(cm, mode.mode);

            if (profile.onCodeModeSet) {
                xui.asyRun(function () {
                    if (!profile.box) return;
                    profile.boxing().onCodeModeSet(profile, mode);
                });
            }

            if (mode.mode == "null") {
                if (!profile.$initialized)
                    profile.$initialized = true;
                if (profile.onRendered)
                    profile.boxing().onRendered(profile, true);
            } else {
                cm.on("rendered", function (cm, finished) {
                    if (!profile.$initialized)
                        profile.$initialized = true;
                    if (profile.onRendered)
                        profile.boxing().onRendered(profile, finished);
                });
            }
            cm.on("change", function (cm, obj) {
                if (profile.$initialized && profile.onValueChanged)
                    profile.boxing().onValueChanged(profile, cm.doc.getValue() != profile.properties.value);
                if (codeType != 'js' && codeType != 'html') return;

                var handled;
                if (obj.origin == "+input") {
                    // igore redo/undo
                    if (obj.text[0]) {
                        if (obj.text[0] == ".") {
                            // only for js file
                            if (codeType != 'js') return;

                            obj.to.ch++;
                            var token = cm.getTokenAt(obj.to), type = token.type;
                            if (type !== null)
                                return;
                            // show suggestion hint for : token.string
                            var pos = cm.getCursor();
                            showDotHint(cm.doc.indexFromPos(pos), {
                                start: ++token.start,
                                end: ++token.end,
                                line: pos.line
                            });
                            handled = true;
                        } else if (obj.text[0] !== " ") {
                            obj.to.ch++;
                            var token = cm.getTokenAt(obj.to), type = token.type;
                            if (type == "variable" || type == "variable-2" || type == "keyword" || type == "property") {
                                var pos = cm.getCursor();
                                if (pos.line == obj.to.line && pos.ch >= token.start && pos.ch <= token.end) {
                                    if ($suggestionShowed)
                                        tryToAdjustHint(token.string, cm.doc.indexFromPos(pos), {
                                            start: token.start,
                                            end: token.end,
                                            line: pos.line
                                        });
                                    else {
                                        if (type == 'property') {
                                            // only for js file
                                            if (codeType != 'js') return;
                                            var t2 = cm.getTokenAt({
                                                line: obj.to.line,
                                                ch: obj.to.ch - token.string.length
                                            });
                                            if (t2.type !== null || t2.string !== '.')
                                                return;
                                            // show suggestion hint for : token.string
                                            showDotHint(cm.doc.indexFromPos(pos) - obj.text.length - 1, null, token.string, {
                                                start: ++t2.start,
                                                end: ++t2.end,
                                                line: pos.line
                                            });
                                        } else {
                                            showVarsHint(token.string, cm.doc.indexFromPos(pos), {
                                                start: token.start,
                                                end: token.end,
                                                line: pos.line
                                            });
                                        }
                                    }
                                    handled = true;
                                }
                            }
                        }
                    }
                } else if (obj.origin == "+delete") {
                    if ($suggestionShowed) {
                        var token = cm.getTokenAt(obj.to), type = token.type, str = token.string;
                        if ($suggestionShowed === true) {
                            if (type == "variable" || type == "variable-2" || type == "keyword") {
                                var pos = cm.getCursor();
                                if (pos.line == obj.to.line && pos.ch >= token.start && pos.ch <= token.end) {
                                    tryToAdjustHint(token.string, cm.doc.indexFromPos(pos), {
                                        start: token.start,
                                        end: token.end,
                                        line: pos.line
                                    });
                                    handled = true;
                                }
                            }
                        } else if ($suggestionShowed === 1) {
                            if (type == "property") {
                                var pos = cm.getCursor();
                                tryToAdjustHint(token.string, cm.doc.indexFromPos(pos), {
                                    start: token.start,
                                    end: token.end,
                                    line: pos.line
                                });
                                handled = true;
                            } else if (type === null && str == ".") {
                                var pos = cm.getCursor();
                                showDotHint(cm.doc.indexFromPos(pos), {
                                    start: ++token.start,
                                    end: ++token.end,
                                    line: pos.line
                                });
                                handled = true;
                            }
                        }
                    }
                }
                if (!handled) {
                    //if hint/hint2 showed, hide it
                    hideSuggestion();
                }
            });
            cm.on("blur", function () {
                //hideSuggestion();
            });
            cm.on("keypress", function (cm, key) {
                if (codeType != 'js' && codeType != 'html') return;
                if ($willshowDotHint && xui.Event.getKey(key)[0] != ".") {
                    hideSuggestion();
                }
            });
            cm.on("keydown", function (cm, key) {
                if (codeType != 'js' && codeType != 'html') return;
                if ($willshowDotHint && xui.Event.getKey(key)[0] != ".") {
                    hideSuggestion();
                }
            });
            cm.on("cursorActivity", function (cm) {
                if (!cm.hasFocus()) return;

                if (codeType != 'js' && codeType != 'html') return;
                if ($suggestionBaseScope) {
                    var pos = cm.getCursor(),
                        scope = $suggestionBaseScope;
                    // not in region
                    if (pos.line !== scope.line || pos.ch < scope.start || pos.ch > scope.end) {
                        hideSuggestion();
                    }
                }
                xui.resetRun("cm_showtips", function () {
                    var state = cm.state.matchHighlighter;
                    if (state) {
                        //only for selection, and matchhighlight
                        if (state.overlay && state.style == "matchhighlight" && cm.doc.somethingSelected()) {
                            var cur = cm.getCursor(),
                                sel = cm.doc.getSelection(),
                                token = cm.getTokenAt(cur);
                            // only for whole word
                            if (sel === token.string) {
                                showDotHint(cm.doc.indexFromPos(cur), {
                                    start: token.start,
                                    end: token.end,
                                    line: cur.line
                                }, token.string);
                            }
                        }
                    }
                }, 200);
            });
        },
        _onresize: function (profile, width, height) {
            var size = arguments.callee.upper.apply(this, arguments);
            profile.getSubNode('BOX').cssSize(size);
            // have to use px here
            if (profile.$cm) profile.$cm.setSize(profile.$px(size.width), profile.$px(size.height));
        }
    }
});
